home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / tos / g__~1 / gplibs15.zoo / dtoa.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-01  |  7.2 KB  |  340 lines

  1. /* 
  2. Copyright (C) 1990 Free Software Foundation
  3.     written by Doug Lea (dl@rocky.oswego.edu)
  4.  
  5. This file is part of the GNU C++ Library.  This library is free
  6. software; you can redistribute it and/or modify it under the terms of
  7. the GNU Library General Public License as published by the Free
  8. Software Foundation; either version 2 of the License, or (at your
  9. option) any later version.  This library is distributed in the hope
  10. that it will be useful, but WITHOUT ANY WARRANTY; without even the
  11. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  12. PURPOSE.  See the GNU Library General Public License for more details.
  13. You should have received a copy of the GNU Library General Public
  14. License along with this library; if not, write to the Free Software
  15. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  16. */
  17.  
  18. #ifdef __GNUG__
  19. #pragma implementation
  20. #endif
  21. #include <builtin.h>
  22. #include <math.h>
  23. #include <values.h>
  24. #include <xallocri.h>
  25.  
  26. extern AllocRing _libgxx_fmtq;
  27.  
  28. #ifndef M_LN2
  29. #define M_LN2        0.69314718055994530942
  30. #define M_LN10        2.30258509299404568402
  31. #endif
  32.  
  33. // OBSOLETE ROUTINE!
  34.  
  35. char* dtoa(double fpnum,  char cvt, int width, int prec)
  36. {
  37.   // set up workspace
  38.  
  39.   // max possible digits <= those need to show all of prec + exp
  40.   // <= ceil(log10(HUGE)) plus space for null, etc.
  41.  
  42.   const int worksiz = int((M_LN2 / M_LN10) * DMAXEXP) + 8; 
  43.  
  44.   // for fractional part
  45.   char  fwork[worksiz];
  46.   char* fw = fwork;
  47.  
  48.   // for integer part
  49.   char  iwork[worksiz];
  50.   char* iworkend = &iwork[sizeof(iwork) - 1];
  51.   char* iw = iworkend;
  52.   *iw = 0;
  53.  
  54.   // for exponent part
  55.  
  56.   const int eworksiz = int(M_LN2 * _DEXPLEN) + 8;
  57.   char  ework[eworksiz];
  58.   char* eworkend = &ework[sizeof(ework) - 1];
  59.   char* ew = eworkend;
  60.   *ew = 0;
  61.  
  62. #if (_IEEE != 0) && (!defined(atarist))
  63.   if (isinf(fpnum))
  64.   {
  65.     char* inffmt = (char *) _libgxx_fmtq.alloc(5);
  66.     char* inffmtp = inffmt;
  67.     if (fpnum < 0)
  68.       *inffmtp++ = '-';
  69.     strcpy(inffmtp, "Inf");
  70.     return inffmt;
  71.   }
  72.  
  73.   if (isnan(fpnum))
  74.   {
  75.     char* nanfmt = (char *) _libgxx_fmtq.alloc(4);
  76.     strcpy(nanfmt, "NaN");
  77.     return nanfmt;
  78.   }
  79. #endif
  80.  
  81.   // grab sign & make non-negative
  82.   int is_neg = fpnum < 0;
  83.   if (is_neg) fpnum = -fpnum;
  84.  
  85.   // precision matters
  86.  
  87.   if (prec > worksiz - 2) // can't have more prec than supported
  88.     prec = worksiz - 2;
  89.   
  90.   double powprec;
  91.   if (prec == 6)
  92.     powprec = 1.0e6;
  93.   else
  94.     powprec = pow(10.0, (long) prec);
  95.  
  96.   double rounder = 0.5 / powprec;
  97.  
  98.   int f_fmt = cvt == 'f' ||
  99.     ((cvt == 'g') && (fpnum == 0.0 || (fpnum >= 1e-4 && fpnum < powprec)));
  100.  
  101.   int iwidth = 0;
  102.   int fwidth = 0;
  103.   int ewidth = 0;
  104.  
  105.   if (f_fmt)  // fixed format
  106.   {
  107.     double ipart;
  108.     double fpart = modf(fpnum, &ipart);
  109.  
  110.     // convert fractional part
  111.  
  112.     if (fpart >= rounder || cvt != 'g')
  113.     {
  114.       fpart += rounder;
  115.       if (fpart >= 1.0)
  116.       {
  117.         ipart += 1.0;
  118.         fpart -= 1.0;
  119.       }
  120.       double ffpart = fpart;
  121.       double ifpart;
  122.       for (int i = 0; i < prec; ++i)
  123.       {
  124.         ffpart = modf(ffpart * 10.0, &ifpart);
  125.         *fw++ = '0' + int(ifpart);
  126.         ++fwidth;
  127.       }
  128.       if (cvt == 'g')  // inhibit trailing zeroes if g-fmt
  129.       {
  130.         for (char* p = fw - 1; p >= fwork && *p == '0'; --p)
  131.         {
  132.           *p = 0;
  133.           --fwidth;
  134.         }
  135.       }
  136.     }
  137.  
  138.     // convert integer part
  139.     if (ipart == 0.0)
  140.     {
  141.       if (cvt != 'g' || fwidth < prec || fwidth < width)
  142.       {
  143.         *--iw = '0'; ++iwidth;
  144.       }
  145.     }
  146.     else if (ipart <= double(MAXLONG)) // a useful speedup
  147.     {
  148.       long li = long(ipart);
  149.       while (li != 0)
  150.       {
  151.         *--iw = '0' + (li % 10);
  152.         li = li / 10;
  153.         ++iwidth;
  154.       }
  155.     }
  156.     else // the slow way
  157.     {
  158.       while (ipart > 0.5)
  159.       {
  160.         double ff = modf(ipart / 10.0, &ipart);
  161.         ff = (ff + 0.05) * 10.0;
  162.         *--iw = '0' + int(ff);
  163.         ++iwidth;
  164.       }
  165.     }
  166.  
  167.     // g-fmt: kill part of frac if prec/width exceeded
  168.     if (cvt == 'g')
  169.     {
  170.       int m = prec;
  171.       if (m < width)
  172.         m = width;
  173.       int adj = iwidth + fwidth - m;
  174.       if (adj > fwidth)
  175.         adj = fwidth;
  176.       if (adj > 0)
  177.       {
  178.         for (char* f = &fwork[fwidth-1]; f >= fwork && adj > 0; --adj, --f)
  179.         {
  180.           --fwidth;
  181.           char ch = *f;
  182.           *f = 0;
  183.           if (ch > '5') // properly round: unavoidable propagation
  184.           {
  185.             int carry = 1;
  186.             for (char* p = f - 1; p >= fwork && carry; --p)
  187.             {
  188.               ++*p;
  189.               if (*p > '9')
  190.                 *p = '0';
  191.               else
  192.                 carry = 0;
  193.             }
  194.             if (carry)
  195.             {
  196.               for (p = iworkend - 1; p >= iw && carry; --p)
  197.               {
  198.                 ++*p;
  199.                 if (*p > '9')
  200.                   *p = '0';
  201.                 else
  202.                   carry = 0;
  203.               }
  204.               if (carry)
  205.               {
  206.                 *--iw = '1';
  207.                 ++iwidth;
  208.                 --adj;
  209.               }
  210.             }
  211.           }
  212.         }
  213.       }
  214.     }
  215.               
  216.   }
  217.   else  // e-fmt
  218.   {
  219.     
  220.     // normalize
  221.     int exp = 0;
  222.     while (fpnum >= 10.0)
  223.     {
  224.       fpnum *= 0.1;
  225.       ++exp;
  226.     }
  227.     double almost_one = 1.0 - rounder;
  228.     while (fpnum > 0.0 && fpnum < almost_one)
  229.     {
  230.       fpnum *= 10.0;
  231.       --exp;
  232.     }
  233.     
  234.     double ipart;
  235.     double fpart = modf(fpnum, &ipart);
  236.  
  237.  
  238.     if (cvt == 'g')     // used up one digit for int part...
  239.     {
  240.       --prec;
  241.       powprec /= 10.0;
  242.       rounder = 0.5 / powprec;
  243.     }
  244.  
  245.     // convert fractional part -- almost same as above
  246.     if (fpart >= rounder || cvt != 'g')
  247.     {
  248.       fpart += rounder;
  249.       if (fpart >= 1.0)
  250.       {
  251.         fpart -= 1.0;
  252.         ipart += 1.0;
  253.         if (ipart >= 10.0)
  254.         {
  255.           ++exp;
  256.           ipart /= 10.0;
  257.           fpart /= 10.0;
  258.         }
  259.       }
  260.       double ffpart = fpart;
  261.       double ifpart;
  262.       for (int i = 0; i < prec; ++i)
  263.       {
  264.         ffpart = modf(ffpart * 10.0, &ifpart);
  265.         *fw++ = '0' + int(ifpart);
  266.         ++fwidth;
  267.       }
  268.       if (cvt == 'g')  // inhibit trailing zeroes if g-fmt
  269.       {
  270.         for (char* p = fw - 1; p >= fwork && *p == '0'; --p)
  271.         {
  272.           *p = 0;
  273.           --fwidth;
  274.         }
  275.       }
  276.     }
  277.  
  278.     
  279.     // convert exponent
  280.  
  281.     char eneg = exp < 0;
  282.     if (eneg) exp = - exp;
  283.  
  284.     while (exp > 0)
  285.     {
  286.       *--ew = '0' + (exp % 10);
  287.       exp /= 10;
  288.       ++ewidth;
  289.     }
  290.  
  291.     while (ewidth < 2)  // ensure at least 2 zeroes
  292.     {
  293.       *--ew = '0';
  294.       ++ewidth;
  295.     }
  296.  
  297.     *--ew = eneg ? '-' : '+';
  298.     *--ew = 'e';
  299.  
  300.     ewidth += 2;
  301.  
  302.     // convert the one-digit integer part
  303.     *--iw = '0' + int(ipart);
  304.     ++iwidth;
  305.     
  306.   }
  307.  
  308.   // arrange everything in returned string
  309.  
  310.   int showdot = cvt != 'g' || fwidth > 0;
  311.  
  312.   int fmtwidth = is_neg + iwidth + showdot + fwidth + ewidth;
  313.   
  314.   int pad = width - fmtwidth;
  315.   if (pad < 0) pad = 0;
  316.   
  317.   char* fmtbase = (char *) _libgxx_fmtq.alloc(fmtwidth + pad + 1);
  318.   char* fmt = fmtbase;
  319.   
  320.   for (int i = 0; i < pad; ++i) *fmt++ = ' ';
  321.   
  322.   if (is_neg) *fmt++ = '-';
  323.   
  324.   for (i = 0; i < iwidth; ++i) *fmt++ = *iw++;
  325.   
  326.   if (showdot)
  327.   {
  328.     *fmt++ = '.';
  329.     fw = fwork;
  330.     for (i = 0; i < fwidth; ++i) *fmt++ = *fw++;
  331.   }
  332.   
  333.   for (i = 0; i < ewidth; ++i) *fmt++ = *ew++;
  334.   
  335.   *fmt = 0;
  336.   
  337.   return fmtbase;
  338. }
  339.  
  340.